#include "../key/taiic_sensor.h"
#include "../key/taiic_rknn.h"
/*---------------isp:add at 2024/4/3------------------*/
 #include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include "isp/uAPI2/rk_aiq_user_api2_debug.h"
#include "isp/rkisp_demo.h"
#include "client_t.h"
/*-----------------------------------*/
using namespace std;
tViFrameDataCallback *s_viFrameDataCallback = NULL; // 定义vi回调方法变量
tAiViSaveEndCallback *s_aivi_save_end = NULL;



int taiic_vi_media_config_init(TAIIC_VI_CTX_S *ctx)
{

    ctx->width = PICTURE_W;        // 图像的宽
    ctx->height = PICTURE_H;       // 图像的高
    ctx->devId = 0;                // 设备id
    ctx->pipeId = ctx->devId;      // 管道id
    ctx->channelId = 0;            // 通道id
    ctx->loopCountSet = PICTURE_C; // 循环次数

    // VI 通道属性
    ctx->stChnAttr.stIspOpt.u32BufCount = 3;
    ctx->stChnAttr.stIspOpt.enMemoryType = VI_V4L2_MEMORY_TYPE_DMABUF;
    ctx->stChnAttr.stIspOpt.bNoUseLibV4L2 = RK_TRUE;
    ctx->stChnAttr.u32Depth = 0;
    ctx->stChnAttr.enPixelFormat = RK_FMT_YUV420SP;
    ctx->stChnAttr.stFrameRate.s32SrcFrameRate = -1;
    ctx->stChnAttr.stFrameRate.s32DstFrameRate = -1;

    ctx->aEntityName = RK_NULL;
    ctx->rgnType = RGN_BUTT;

    ctx->stDebugFile.bCfg = RK_FALSE;

    if (!ctx->stChnAttr.u32Depth)
    {
        RK_LOGE("depth need > 0 when vi not bind any other module!\n");
        ctx->stChnAttr.u32Depth = ctx->stChnAttr.stIspOpt.u32BufCount;
        RK_LOGD("=====depth is %d=======\n", ctx->stChnAttr.u32Depth);
    }

    if (ctx->stDebugFile.bCfg == RK_TRUE)
    {
        // 保存数据的路径
        memcpy(&ctx->stDebugFile.aFilePath, LIPSPATH, strlen(LIPSPATH));
        DIR *mydir = NULL;
        if ((mydir = opendir(ctx->stDebugFile.aFilePath)) == NULL) //
        {
            bool ret = mkdir(ctx->stDebugFile.aFilePath, 0755);
            RK_LOGD("%s created sucess!/n", ctx->stDebugFile.aFilePath);
        }

        snprintf(ctx->stDebugFile.aFileName, MAX_VI_FILE_PATH_LEN,
                 "session_%d_%d_%d.YUV", ctx->devId, ctx->pipeId, ctx->channelId);

        RK_LOGD("==== FILE IS %s========\n", ctx->stDebugFile.aFileName);
    }

    if (ctx->aEntityName != RK_NULL)
        memcpy(ctx->stChnAttr.stIspOpt.aEntityName, ctx->aEntityName, strlen(ctx->aEntityName));

    ctx->isEnable = RK_TRUE;
    return RK_SUCCESS;
}

RK_S32 taiic_vi_get_release_frame_loop(TAIIC_VI_CTX_S *ctx)
{
    RK_S32 s32Ret;
    RK_S32 loopCount = 0;
    RK_S32 waitTime = 500; /// 500

    // test use getframe&release_frame
    s32Ret = taiic_vi_init(ctx);

    if (s32Ret != RK_SUCCESS)
    {
        RK_LOGE("vi %d:%d init failed:%x", ctx->devId, ctx->channelId, s32Ret);
        goto __FAILED;
    }
    // freeze test
    RK_MPI_VI_SetChnFreeze(ctx->pipeId, ctx->channelId, ctx->bFreeze);

    while (loopCount < ctx->loopCountSet)
    {
        // RK_LOGD("===loopcountset is %d, now is %d===\n", ctx->loopCountSet,loopCount );

        // 5.get the frameinput_data[0][PICTURinput_data[0][PICTURE_H * hnow + i][PICTURE_W * wnow + j][cnow]E_H * hnow + i][PICTURE_W * wnow + j][cnow]
        s32Ret = RK_MPI_VI_GetChnFrame(ctx->pipeId, ctx->channelId, &ctx->stViFrame, waitTime);
        // RK_LOGI("=====5. GET CHN FRAME========\n");
        if (s32Ret == RK_SUCCESS)
        {
            RK_U64 nowUs = TEST_COMM_GetNowUs();
            // 获取图像数据的指针
            void *data = RK_MPI_MB_Handle2VirAddr(ctx->stViFrame.stVFrame.pMbBlk);
            // memcpy(input_data[0] + loopCount, (RK_U8*)data, MODEL_H*MODEL_W);

            if (ctx->loopCountSet == 51) // yuyinzu_51 loop
            {
                // RK_LOGD("===set 51==\n");
                if (s_viFrameDataCallback != NULL) // 第一帧可用
                {
                    s_viFrameDataCallback(data, loopCount);
                }
            }
            else
            {
                RK_LOGD("===set other==\n");
                if (s_viFrameDataCallback != NULL && loopCount > 0) // 真实使用时，去掉第一帧，不可用
                {
                    s_viFrameDataCallback(data, loopCount - 1);
                }
            }
            usleep(1 * 1000);

            // 7.release the frame
            s32Ret = RK_MPI_VI_ReleaseChnFrame(ctx->pipeId, ctx->channelId, &ctx->stViFrame);
            // RK_LOGI("========7. RELEASE THE FRAME==========\n");
            if (s32Ret != RK_SUCCESS)
            {
                RK_LOGE("RK_MPI_VI_ReleaseChnFrame fail %d", s32Ret);
            }
            // RK_LOGI("=====loopcount %d====== \n", loopCount);
            loopCount++;
        }
        else
        {
            RK_LOGE("RK_MPI_VI_GetChnFrame timeout %d", s32Ret);
            break;
        }

        // if (loopCount == ctx->loopCountSet)
        // {
        //     saveDataSet((RK_U8 *)input_data, PICTURE_C * PICTURE_H * PICTURE_W, 0, 0, 0);
        // }
    }

__FAILED:

    // 9. disable one chn
    s32Ret = RK_MPI_VI_DisableChn(ctx->pipeId, ctx->channelId);
    if (s32Ret != RK_SUCCESS)
    {
        RK_LOGE("RK_MPI_VI_DisableChn %d", s32Ret);
    }

    // 10.disable dev(will diabled all chn)
    s32Ret = RK_MPI_VI_DisableDev(ctx->devId);
    if (s32Ret != RK_SUCCESS)
    {
        RK_LOGE("RK_MPI_VI_DisableDev %d", s32Ret);
    }
    // if(ctx->loopCountSet == 51)
    // {
    //     system("/oem/usr/bin/kill_rkaiq_taiic.sh");
    // }

        // close led
    system("echo 0 >/sys/class/pwm/pwmchip1/pwm0/enable");
    system("echo a > /sys/devices/virtual/adw/adwdev/adwgpio");

    return s32Ret;
}

/// <summary>
/// 初始化 vi
/// </summary>
/// <param name="ctx"></param>
/// <returns></returns>
RK_S32 taiic_vi_init(TAIIC_VI_CTX_S *ctx)
{
    RK_S32 s32Ret = RK_FAILURE;

    // 0. get dev config status
    s32Ret = RK_MPI_VI_GetDevAttr(ctx->devId, &ctx->stDevAttr);
    // RK_LOGI("======00 results %X=====saveDataSet\n", s32Ret);
    if (s32Ret == RK_ERR_VI_NOT_CONFIG)
    {
        // 0-1.config dev
        s32Ret = RK_MPI_VI_SetDevAttr(ctx->devId, &ctx->stDevAttr);

        if (s32Ret != RK_SUCCESS)
        {
            RK_LOGE("RK_MPI_VI_SetDevAttr %x", s32Ret);
            goto __FAILED;
        }
        // RK_LOGI("=====0-1 %d=======\n", s32Ret);
    }
    else
    {
        RK_LOGI("RK_MPI_VI_SetDevAttr already");
    }
    // 1.get  dev enable status
    s32Ret = RK_MPI_VI_GetDevIsEnable(ctx->devId);
    // RK_LOGI("=====11 %X======\n", s32Ret);
    if (s32Ret != RK_SUCCESS)
    {
        // 1-2.enable dev
        s32Ret = RK_MPI_VI_EnableDev(ctx->devId);
        if (s32Ret != RK_SUCCESS)
        {
            RK_LOGE("RK_MPI_VI_EnableDev %x", s32Ret);
            goto __FAILED;
        }
        // RK_LOGI("====== ENABLE DEV =======\n");
        // 1-3.bind dev/pipe
        ctx->stBindPipe.u32Num = ctx->pipeId;
        ctx->stBindPipe.PipeId[0] = ctx->pipeId;
        s32Ret = RK_MPI_VI_SetDevBindPipe(ctx->devId, &ctx->stBindPipe);
        if (s32Ret != RK_SUCCESS)
        {
            RK_LOGE("RK_MPI_VI_SetDevBindPipe %x", s32Ret);
            goto __FAILED;
        }
        // RK_LOGI("====== BIND PIPE========\n");
    }
    else
    {
        RK_LOGI("RK_MPI_VI_EnableDev already");
    }

    // 2.config channel
    ctx->stChnAttr.stSize.u32Width = ctx->width;
    ctx->stChnAttr.stSize.u32Height = ctx->height;
    ctx->stChnAttr.enCompressMode = ctx->enCompressMode;
    ctx->stChnAttr.u32Depth = 1;
    ctx->stChnAttr.bMirror = ctx->bMirror;
    ctx->stChnAttr.bFlip = ctx->bFlip;
    s32Ret = RK_MPI_VI_SetChnAttr(ctx->pipeId, ctx->channelId, &ctx->stChnAttr);

    if (s32Ret != RK_SUCCESS)
    {
        RK_LOGE("RK_MPI_VI_SetChnAttr %x", s32Ret);
        goto __FAILED;
    }
    // RK_LOGI("======22 %d=======\n", s32Ret);

    ctx->stViRgn.stRgnAttr.enType = (RGN_TYPE_E)ctx->rgnType;
    RK_LOGI("RGN Type = %d", ctx->stViRgn.stRgnAttr.enType);
    ctx->stViRgn.stRgnChnAttr.bShow = RK_TRUE;

    // open fd before enable chn will be better

    // 3.enable channel
    s32Ret = RK_MPI_VI_EnableChn(ctx->pipeId, ctx->channelId);
    if (s32Ret != RK_SUCCESS)
    {
        RK_LOGE("RK_MPI_VI_EnableChn %x", s32Ret);
        goto __FAILED;
    }
    // RK_LOGI("======3. ENABLE CHANNE========\n");

    // 4.save debug file
    if (ctx->stDebugFile.bCfg)
    {
        s32Ret = RK_MPI_VI_ChnSaveFile(ctx->pipeId, ctx->channelId, &ctx->stDebugFile);
        // RK_LOGI("RK_MPI_VI_ChnSaveFile %x", s32Ret);
    }

__FAILED:
    return s32Ret;
}

int taiic_vi_frame_data_callback(tViFrameDataCallback vi_frame_data)
{
    s_viFrameDataCallback = vi_frame_data;
    return 1;
}


//ai_vi frame data callback
void aivi_save_end_callback(tAiViSaveEndCallback aivi_save_end)
{
    if (aivi_save_end != NULL)
    {
        s_aivi_save_end = aivi_save_end;
    }
}

int taiic_vi_rknn_input_refresh(TOOLKIT_MODEL_CTX_S *ctx, RK_U8 *input_ptr)
{

    // Copy input data to input tensor memory
    int width = ctx->input_attrs[0].dims[2];
    int stride = ctx->input_attrs[0].w_stride;
    RK_LOGI("====width is %d, stride is %d", width, stride);
    if (width == stride)
    {
        RK_LOGI("===== == ======\n");
        memcpy(ctx->input_mems[0]->virt_addr, input_ptr, width * ctx->input_attrs[0].dims[1] * ctx->input_attrs[0].dims[3]);
        RK_LOGI("==data length is %d===\n", (width * ctx->input_attrs[0].dims[1] * ctx->input_attrs[0].dims[3]));
        // for (int i = 0; i < 50; i++)
        // {
        //     RK_LOGI("==data is %d==\n", *input_ptr);
        //     input_ptr++;
        // }
    }
    else
    {
        RK_LOGI("===== != ========\n");
        int height = ctx->input_attrs[0].dims[1];
        int channel = ctx->input_attrs[0].dims[3];
        // copy from src to dst with stride
        RK_U8 *src_ptr = input_ptr;

        RK_U8 *dst_ptr = (RK_U8 *)ctx->input_mems[0]->virt_addr;
        // width-channel elements
        int src_wc_elems = width * channel;
        int dst_wc_elems = stride * channel;
        for (int h = 0; h < height; ++h)
        {
            memcpy(dst_ptr, src_ptr, src_wc_elems);
            src_ptr += src_wc_elems;
            dst_ptr += dst_wc_elems;
        }
    }

    // Set input tensor memory
    if (rknn_set_io_mem(ctx->context, ctx->input_mems[0], &ctx->input_attrs[0]) < 0)
    {
        RK_LOGE("rknn_set_io_mem fail! ");
        return RK_FAILURE;
    }

    return RK_SUCCESS;
}








AUDIO_SOUND_MODE_E find_sound_mode(RK_S32 ch)
{
    AUDIO_SOUND_MODE_E channel = AUDIO_SOUND_MODE_BUTT;
    switch (ch)
    {
    case 1:
        channel = AUDIO_SOUND_MODE_MONO;
        break;
    case 2:
        channel = AUDIO_SOUND_MODE_STEREO;
        break;
    default:
        RK_LOGE("channel = %d not support", ch);
        return AUDIO_SOUND_MODE_BUTT;
    }

    return channel;
}


RK_VOID test_bcd_callback()
{
    RK_LOGI("baby cry callback successed\n");
}


int ResamplePcm(short *pInAudioData, RK_U32 nInAudioLen, short *pOutAudioData, int &nOutAudioLen, TEST_PCM_TRANS method_n)
{

    short *sSampleIn = pInAudioData;

    int nFrequency = 0;

    while (sSampleIn - pInAudioData < nInAudioLen)

    {
        if (method_n == PCM_8_TO_16)
        {
            memcpy((char *)(pOutAudioData + nFrequency), (char *)sSampleIn, 2);

            nFrequency++;

            memcpy((char *)(pOutAudioData + nFrequency), (char *)sSampleIn, 2);

            nFrequency++;

            sSampleIn++;
        }
        else if (method_n == PCM_16_TO_8)
        {
            memcpy((char *)(pOutAudioData + nFrequency), (char *)sSampleIn, 2);

            nFrequency++;
            sSampleIn++;
            sSampleIn++;
        }
        else
        {
            return 0;
        }
    }

    nOutAudioLen = nFrequency * 2;
    return 1;
}

static bool get_value_from_file(const char* path, int* value, int* frameId)
{
    const char *delim = " ";
    char buffer[16] = {0};
    int fp;

    fp = open(path, O_RDONLY | O_SYNC);
    if (fp) {
        if (read(fp, buffer, sizeof(buffer)) > 0) {
            char *p = nullptr;

            p = strtok(buffer, delim);
            if (p != nullptr) {
                *value = atoi(p);
                p = strtok(nullptr, delim);
                if (p != nullptr)
                    *frameId = atoi(p);
            }
        }
        close(fp);
        return true;
    }

    return false;
}
static int creat_yuv_dir(const char* path, demo_context_t *ctx)
{
    printf("creat_yuv_dir\n");
    time_t now;
    struct tm* timenow;

    if (!path)
        return -1;

    time(&now);
    timenow = localtime(&now);
    snprintf(ctx->yuv_dir_path, sizeof(ctx->yuv_dir_path),
             "%s/yuv_%04d-%02d-%02d_%02d-%02d-%02d",
             path,
             timenow->tm_year + 1900,
             timenow->tm_mon + 1,
             timenow->tm_mday,
             timenow->tm_hour,
             timenow->tm_min,
             timenow->tm_sec);

    // printf("mkdir %s for capturing yuv!\n", yuv_dir_path);

    if(mkdir(ctx->yuv_dir_path, 0755) < 0) {
        printf("mkdir %s error!!!\n", ctx->yuv_dir_path);
        return -1;
    }
    ctx->_is_yuv_dir_exist = true;
    return 0;
}
static int write_yuv_to_file(const void *p,int size, int sequence, demo_context_t *ctx)
{
    printf("***write_yuv_to_file***\n");
    char file_name[64] = {0};

    snprintf(file_name, sizeof(file_name),
             "%s/frame%d.yuv",
             ctx->yuv_dir_path,
             sequence);
    ctx->fp = fopen(file_name, "wb+");
    if (ctx->fp == NULL) {
        ERR("fopen yuv file %s failed!\n", file_name);
        return -1;
    }

    fwrite(p, size, 1, ctx->fp);
    //fflush(ctx->fp);

    if (ctx->fp) {
        fclose(ctx->fp);
        ctx->fp = NULL;
    }

    for (int i = 0; i < ctx->capture_yuv_num; i++)
        printf("<");

    printf("\n");
    // printf("write frame%d yuv\n", sequence);

    return 0;
}


void process_image(void *p, int sequence, int size, demo_context_t *ctx,int flg)
{      
    if (ctx->fp) {
        // RK_LOGW("size=%d,isp_img_cnt=%d\n",size,flg);
        if((s_viFrameDataCallback != NULL)&&(flg>(SKIP_ISP_FRAMES-1))) //vi 回调
        {
            s_viFrameDataCallback(p, flg-SKIP_ISP_FRAMES);
            //save data to out.yuv file
            // fwrite(p, size, 1, ctx->fp);
            /*fflush(ctx->fp);
            fsync(fileno(ctx->fp));*/
        }
    } 
    // else if (ctx->fp && sequence >= ctx->skipCnt && (ctx->outputCnt--) == 0) {
       
            // fclose(ctx->fp);
            // ctx->fp = NULL;
        //}
    else if (ctx->writeFileSync) 
    {
        printf("This is line %d  in file==\n", __LINE__);
        int ret = 0;
        if (!ctx->is_capture_yuv) {
            char file_name[32] = {0};
            int rawFrameId = 0;

            snprintf(file_name, sizeof(file_name), "%s/%s",
                     CAPTURE_RAW_PATH, CAPTURE_CNT_FILENAME);
            get_value_from_file(file_name, &ctx->capture_yuv_num, &rawFrameId);

            /*
             * printf("%s: rawFrameId: %d, sequence: %d\n", __FUNCTION__,
             *        rawFrameId, sequence);
             */

            sequence += 1;
            if (ctx->capture_yuv_num > 0 && \
                    ((sequence >= rawFrameId && rawFrameId > 0) || sequence < 2))
                ctx->is_capture_yuv = true;
        }

        if (ctx->is_capture_yuv) {
            if (!ctx->_is_yuv_dir_exist) {
                creat_yuv_dir(DEFAULT_CAPTURE_RAW_PATH, ctx);
            }

            if (ctx->_is_yuv_dir_exist) {
                write_yuv_to_file(p, size, sequence, ctx);
                rk_aiq_uapi2_debug_captureRawNotify(ctx->aiq_ctx);
            }

            if (ctx->capture_yuv_num-- == 0) {
                ctx->is_capture_yuv = false;
                ctx->_is_yuv_dir_exist = false;
            }
        }
    }
}